﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Service.Activity.SDK;
using Services.Identity.Domain.Entities;
using Services.Identity.Infrastructure;
using System.Security.Claims;
using Zack.JWT;

namespace Services.Identity.WebApi.Service;

[Authorize]
public class UserMessageHub(IOptionsSnapshot<JWTOptions> jWTOptions, ITokenService tokenService, IHttpClientFactory httpClientFactory, MyIdentityDbContext dbContext) : Hub
{
    private readonly ActivityClient activityClient = new(tokenService, jWTOptions.Value, httpClientFactory);
    private readonly MyIdentityDbContext dbContext = dbContext;
    private static List<ConnectionUser> Users = [];
    public async Task SendMessageForActivity(string message, long activityId)
    {
        var volunteers = await this.activityClient.GetActivityVolunteerAsync(activityId);
        //判断是否有参与者
        if (volunteers.Count == 0)
        {
            var userId = this.Context.User!.FindFirst(ClaimTypes.NameIdentifier)!.Value;
            await this.Clients.User(userId).SendAsync(MessageType.SendPrivateMessage, "还没有任何人参加到这个活动");
            return;
        }
        var userMessage = UserMessage.Create(activityId, message);
        this.dbContext.Messages.Add(userMessage);
        foreach (var volunteer in volunteers)
        {
            var user = Users.Where(x => x.Id == volunteer.VolunteerId).SingleOrDefault();
            if (user == null)
            {
                var unsentUser = UnsentUser.Create(volunteer.VolunteerId);
                userMessage.SetUnsentUsers([unsentUser]);
            }
            else
            {
                await this.Clients.User(user.Id.ToString()).SendAsync(MessageType.SendActivityMessage, new SendMessage(activityId, DateTime.Now, message, userMessage.MessageId));
            }
        }
        await this.dbContext.SaveChangesAsync();
    }
    public override async Task OnConnectedAsync()
    {
        //连接上
        await base.OnConnectedAsync();
        //用户id
        var id = Convert.ToInt64(Context.User!.FindFirst(ClaimTypes.NameIdentifier)!.Value);
        //查询用户
        var user = Users.Where(u => u.Id == id).SingleOrDefault();
        //判断用户是否存在，否则添加集合
        if (user == null)
        {
            user = new ConnectionUser("", id, Context.ConnectionId);
            Users.Add(user);
            var messages = await this.dbContext.Messages.Include(x => x.UnsentUsers).Where(x => x.UnsentUsers.Any(x => x.UserId == id)).ToListAsync();
            if (messages.Count != 0)
            {
                foreach (var message in messages)
                {
                    await this.Clients.User(id.ToString()).SendAsync(MessageType.SendActivityMessage, new SendMessage(message.ActivityId, message.CreateTime, message.Message, message.MessageId));
                    var unsentUser = message.UnsentUsers.SingleOrDefault(x => x.UserId == id)!;
                    unsentUser.Send();
                }
                await this.dbContext.SaveChangesAsync();
            }
        }
    }
    public override Task OnDisconnectedAsync(Exception? exception)
    {
        //用户id
        var id = Convert.ToInt64(Context.User!.FindFirst(ClaimTypes.NameIdentifier)!.Value);
        var user = Users.Where(p => p.Id == id).FirstOrDefault();
        //判断用户是否存在，存在则删除
        if (user != null)
        {
            //删除用户
            Users.Remove(user);
        }
        return base.OnDisconnectedAsync(exception);
    }
    private class ConnectionUser(string name, long id, string connectionId)
    {
        /// <summary>
        /// 连接ID
        /// </summary>
        public string ConnectionID { get; set; } = connectionId;

        /// <summary>
        /// 用户名称
        /// </summary>
        public string Name { get; set; } = name;
        /// <summary>
        /// 用户id
        /// </summary>
        public long Id { get; set; } = id;
    }
    private class SendMessage(long activityId, DateTime createTime, string message, long messageId)
    {
        public long MessageId { get; set; } = messageId;
        public long ActivityId { get; set; } = activityId;
        public DateTime CreateTime { get; set; } = createTime;
        public string Message { get; set; } = message;
    }
    private static class MessageType
    {
        public const string SendPrivateMessage = "sendPrivateMessage";
        public const string SendActivityMessage = "sendActivityMessage";
    }
}

